import {
  type AxiosInstance,
  type InternalAxiosRequestConfig,
  type AxiosResponse,
  AxiosError
} from 'axios'
import { resolveResError } from './helpers'
import { useAuthStore } from '@/stores'
import { storeToRefs } from 'pinia'
interface CustomAxiosRequestConfig extends InternalAxiosRequestConfig {
  needToken?: boolean
  needTip?: boolean
}

interface CustomAxiosResponse extends AxiosResponse {
  config: CustomAxiosRequestConfig
}

interface CustomError extends Error {
  code?: string | number
}

interface RejectError {
  code: string | number
  message: string
  error: any
}

export function setupInterceptors(axiosInstance: AxiosInstance): void {
  function reqResolve(config: CustomAxiosRequestConfig): CustomAxiosRequestConfig {
    const authStore = useAuthStore()
    const { accessToken } = storeToRefs(authStore)
    if (config.needToken === false) {
      return config
    }

    if (accessToken.value) {
      config.headers = config.headers || {}
      config.headers.Authorization = `Bearer ${accessToken.value}`
    }

    return config
  }

  function reqReject(error: AxiosError): Promise<AxiosError> {
    return Promise.reject(error)
  }

  const SUCCESS_CODES = [0, 200, 201, 204]
  function resResolve(response: CustomAxiosResponse): Promise<any> {
    const { data, status, config, statusText, headers } = response
    if (headers['content-type']?.includes('json')) {
      if (SUCCESS_CODES.includes(data?.code)) {
        return Promise.resolve(data)
      }
      const code = data?.code ?? status

      const needTip = config?.needTip !== false

      const message = resolveResError(code, data?.message ?? statusText, needTip)

      return Promise.reject({ code, message, error: data ?? response })
    }
    return Promise.resolve(data ?? response)
  }

  async function resReject(error: AxiosError): Promise<RejectError> {
    if (!error || !error.response) {
      const code = (error as CustomError)?.code
      const message = resolveResError(Number(code), error.message)
      return Promise.reject({ code, message, error })
    }

    const { data, status, config } = error.response as CustomAxiosResponse
    const code = (data as any)?.code ?? status

    const needTip = (config as CustomAxiosRequestConfig)?.needTip !== false
    const message = resolveResError(code, (data as any)?.message ?? error.message, needTip)
    return Promise.reject({ code, message, error: error.response?.data || error.response })
  }

  axiosInstance.interceptors.request.use(reqResolve, reqReject)
  axiosInstance.interceptors.response.use(resResolve, resReject)
}
